package com.hsytech.dijiebao.view.pulltozoom;

import com.hsytech.dijiebao.R;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;


/**
 * Author: ZhuWenWu Version V1.0 Date: 2014/11/7 14:18. Description: Modification History: Date Author Version Description ----------------------------------------------------------------------------------- 2014/11/7 ZhuWenWu 1.0 1.0 Why & What is modified:
 */
public abstract class PullToZoomBase<T extends View> extends LinearLayout implements IPullToZoom<T> {
	private static final float FRICTION = 2.0f;
	protected T mRootView;
	protected View mHeaderView;// 头部View
	protected View mZoomView;// 缩放拉伸View

	protected int mScreenHeight;
	protected int mScreenWidth;

	private boolean isZoomEnabled = true;
	private boolean isParallax = true;
	private boolean isZooming = false;
	private boolean isHideHeader = false;

	private int mTouchSlop;
	private boolean mIsBeingDragged = false;
	private float mLastMotionY;
	private float mLastMotionX;
	private float mInitialMotionY;
	private float mInitialMotionX;
	private OnPullZoomListener onPullZoomListener;

	public PullToZoomBase(Context context) {
		this(context, null);
	}

	public PullToZoomBase(Context context, AttributeSet attrs) {
		super(context, attrs);

		init(context, attrs);
	}

	private void init(Context context, AttributeSet attrs) {
		setGravity(Gravity.CENTER);

		ViewConfiguration config = ViewConfiguration.get(context);
		mTouchSlop = config.getScaledTouchSlop();

		DisplayMetrics localDisplayMetrics = new DisplayMetrics();
		((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
		mScreenHeight = localDisplayMetrics.heightPixels;
		mScreenWidth = localDisplayMetrics.widthPixels;

		// Refreshable View
		// By passing the attrs, we can add ListView/GridView params via XML
		mRootView = createRootView(context, attrs);

		if (attrs != null) {
			LayoutInflater mLayoutInflater = LayoutInflater.from(getContext());
			// 初始化状态View
			TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.PullToZoomView);

			int zoomViewResId = a.getResourceId(R.styleable.PullToZoomView_zoomView, 0);
			if (zoomViewResId > 0) {
				mZoomView = mLayoutInflater.inflate(zoomViewResId, null, false);
			}

			int headerViewResId = a.getResourceId(R.styleable.PullToZoomView_headerView, 0);
			if (headerViewResId > 0) {
				mHeaderView = mLayoutInflater.inflate(headerViewResId, null, false);
			}

			isParallax = a.getBoolean(R.styleable.PullToZoomView_isHeaderParallax, true);

			// Let the derivative classes have a go at handling attributes, then
			// recycle them...
			handleStyledAttributes(a);
			a.recycle();
		}
		addView(mRootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
	}

	public void setOnPullZoomListener(OnPullZoomListener onPullZoomListener) {
		this.onPullZoomListener = onPullZoomListener;
	}

	@Override
	public T getPullRootView() {
		return mRootView;
	}

	@Override
	public View getZoomView() {
		return mZoomView;
	}

	@Override
	public View getHeaderView() {
		return mHeaderView;
	}

	@Override
	public boolean isPullToZoomEnabled() {
		return isZoomEnabled;
	}

	@Override
	public boolean isZooming() {
		return isZooming;
	}

	@Override
	public boolean isParallax() {
		return isParallax;
	}

	@Override
	public boolean isHideHeader() {
		return isHideHeader;
	}

	public void setZoomEnabled(boolean isZoomEnabled) {
		this.isZoomEnabled = isZoomEnabled;
	}

	public void setParallax(boolean isParallax) {
		this.isParallax = isParallax;
	}

	public void setHideHeader(boolean isHideHeader) {// header显示才能Zoom
		this.isHideHeader = isHideHeader;
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		if (!isPullToZoomEnabled() || isHideHeader()) {
			return false;
		}

		final int action = event.getAction();

		if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
			mIsBeingDragged = false;
			return false;
		}

		if (action != MotionEvent.ACTION_DOWN && mIsBeingDragged) {
			return true;
		}
		switch (action) {
		case MotionEvent.ACTION_MOVE: {
			if (isReadyForPullStart()) {
				final float y = event.getY(), x = event.getX();
				final float diff, oppositeDiff, absDiff;

				// We need to use the correct values, based on scroll
				// direction
				diff = y - mLastMotionY;
				oppositeDiff = x - mLastMotionX;
				absDiff = Math.abs(diff);

				if (absDiff > mTouchSlop && absDiff > Math.abs(oppositeDiff)) {
					if (diff >= 1f && isReadyForPullStart()) {
						mLastMotionY = y;
						mLastMotionX = x;
						mIsBeingDragged = true;
					}
				}
			}
			break;
		}
		case MotionEvent.ACTION_DOWN: {
			if (isReadyForPullStart()) {
				mLastMotionY = mInitialMotionY = event.getY();
				mLastMotionX = mInitialMotionX = event.getX();
				mIsBeingDragged = false;
			}
			break;
		}
		}

		return mIsBeingDragged;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (!isPullToZoomEnabled() || isHideHeader()) {
			return false;
		}

		if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
			return false;
		}

		switch (event.getAction()) {
		case MotionEvent.ACTION_MOVE: {
			if (mIsBeingDragged) {
				mLastMotionY = event.getY();
				mLastMotionX = event.getX();
				pullEvent();
				isZooming = true;
				return true;
			}
			break;
		}

		case MotionEvent.ACTION_DOWN: {
			if (isReadyForPullStart()) {
				mLastMotionY = mInitialMotionY = event.getY();
				mLastMotionX = mInitialMotionX = event.getX();
				return true;
			}
			break;
		}

		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP: {
			if (mIsBeingDragged) {
				mIsBeingDragged = false;
				// If we're already refreshing, just scroll back to the top
				if (isZooming()) {
					smoothScrollToTop();
					if (onPullZoomListener != null) {
						onPullZoomListener.onPullZoomEnd();
					}
					isZooming = false;
					return true;
				}
				return true;
			}
			break;
		}
		}
		return false;
	}

	private void pullEvent() {
		final int newScrollValue;
		final float initialMotionValue, lastMotionValue;

		initialMotionValue = mInitialMotionY;
		lastMotionValue = mLastMotionY;

		newScrollValue = Math.round(Math.min(initialMotionValue - lastMotionValue, 0) / FRICTION);

		pullHeaderToZoom(newScrollValue);
		if (onPullZoomListener != null) {
			onPullZoomListener.onPullZooming(newScrollValue);
		}
	}

	protected abstract void pullHeaderToZoom(int newScrollValue);

	public abstract void setHeaderView(View headerView);

	public abstract void setZoomView(View zoomView);

	protected abstract T createRootView(Context context, AttributeSet attrs);

	protected abstract void smoothScrollToTop();

	protected abstract boolean isReadyForPullStart();

	public interface OnPullZoomListener {
		public void onPullZooming(int newScrollValue);

		public void onPullZoomEnd();
	}
}
